home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Games / net3d-0.08 / game.c < prev    next >
C/C++ Source or Header  |  1995-06-22  |  28KB  |  1,163 lines

  1. /* game.c
  2.  *
  3.  * gameplay related functions
  4.  */
  5. #include "net3d.h"
  6.  
  7. static int gkeys[]={XK_Left, XK_Right, XK_Up, XK_Down, XK_a,
  8.             XK_z, XK_s, XK_o, XK_p, XK_Return, XK_q,
  9.             XK_w,XK_l,XK_j,XK_b,XK_i,XK_k};
  10.  
  11. char fakepipe[1000];        /* place single-player mode messages
  12.                  * go through. */
  13.  
  14. bool buildicons = false;    /* is the build icons bar open? */
  15.  
  16. static int wallcost[]={0,2,2, 3,3,3,3, 4,4,4,4, 4, 3, 6};
  17.                 /* costs of the various wall sections */
  18.  
  19. int ctrlc = 0;            /* has control-c been hit? */
  20.  
  21.  
  22. /* read 0 or more keyboard events, and for each either transmit a
  23.  * message to the server or change the viewing mode
  24.  */
  25. void readkeys(int *vmode, struct vehicle *drive,struct vehicle *vh, 
  26.  double ctime)
  27. {
  28. XEvent event;            /* message from X */
  29. KeySym key;            /* key pressed */
  30. int keyread;
  31.  
  32. double velocity;        /* motion attributes */
  33. double angle;
  34. double altitude;
  35. double tangle;
  36. double turret_ang;
  37.  
  38. static double movefactor = 1;    /* if a key is held down, then the angle
  39.                  * change factor is increased until a frame
  40.                  * in which no key is pressed. */
  41. Bool keyhit = False;
  42.  
  43. char msg[1200]="";        /* complete message to send */
  44.  
  45.  
  46. /* In single player mode, instead of using file descriptors to pass
  47.  * commands between readkeys() and readnet(), the string fakepipe
  48.  * is used to store commands intermediately.
  49.  */
  50. if (singlep) {
  51.     sprintf(fakepipe,"%f ",gametime());
  52.     }
  53.  
  54. /* extract attribute from vehicle, for storing into temporary
  55.  * variables (if the player is alive).
  56.  */
  57. if (drive) {
  58.     velocity    = drive->velocity;
  59.     angle        = drive->angle;
  60.     altitude    = drive->parts[0]->pos.z;
  61.     tangle        = findturret(drive) ? findturret(drive)->angle : 0.0;
  62.     turret_ang  = drive->turret_ang;
  63.     }
  64.  
  65. /* If control-c is hit, explode this player, close the game window and
  66.  * fork off a new process to convince the server that this player is still
  67.  * around. This prevents one player ending the game for everyone by breaking
  68.  * their client process.
  69.  */
  70. if (ctrlc) {
  71.     if (drive)
  72.         nprintf(sock,"x %d 0.0\nd\n",drive->vid);
  73.     XDestroyWindow(display,view_win);
  74.     XFreePixmap(display,view_pm);
  75.     XFlush(display);
  76.     if (fork())
  77.         exit(0);
  78.     else
  79.         deadloop();
  80.     }
  81.  
  82. while(XPending(display)) {
  83.     char com[100]="";    /* one command */
  84.         XNextEvent(display,&event);
  85.     /*
  86.     printf("got event %d\n",event.type);
  87.     */
  88.         switch(event.type) {
  89.         case KeyPress:
  90.         keyhit = True;
  91.         if (movefactor < 20)
  92.             movefactor += 1.0;
  93.         if (!drive) {
  94.             /* The player is dead, so forget about any keypress
  95.              * events.
  96.              */
  97.             break;
  98.             }
  99.         key = XLookupKeysym(&event.xkey,0);
  100.                 keyread = key;
  101.         /* printf("keyread = %d\n",keyread); */
  102.  
  103.         /* A change in the view mode */
  104.         if (keyread==XK_1) {
  105.             *vmode=1;
  106.             }
  107.         else if (keyread==XK_2) {
  108.             *vmode=2;
  109.             }
  110.         else if (keyread==XK_3) {
  111.             *vmode=3;
  112.             }
  113.         else if (keyread==XK_4) {
  114.             *vmode=4;
  115.             }
  116.         else if (keyread==XK_5) {
  117.             *vmode=5;
  118.             }
  119.         else if (keyread==XK_6) {
  120.             *vmode=6;
  121.             }
  122.         else if (keyread==XK_7) {
  123.             *vmode=7;
  124.             }
  125.         else if (keyread==XK_8) {
  126.             *vmode=8;
  127.             }
  128.         else if (keyread==XK_9) {
  129.             struct vehicle *cv=NULL;
  130.  
  131.             *vmode=9;
  132.             /* Find the next possible interesting vehicle to
  133.              * view from.
  134.              */
  135.             /* first find the current one.. */
  136.             if (drive->vm9vid != -1) {
  137.                 cv = findbyvid(vh,drive->vm9vid);
  138.                 }
  139.             if (!cv) {
  140.                 /* Current one has been destroyed! */
  141.                 cv = vh;
  142.                 }
  143.             /* now find the next suitable target */
  144.             do {
  145.                 cv = cv->next;
  146.                 if (!cv) {
  147.                     /* run off end of list.. */
  148.                     cv=vh;
  149.                     }
  150.                 } while(boring(cv));
  151.             drive->vm9vid = cv->vid;
  152.             }
  153.         else if (keyread==gkeys[11]) {
  154.             /* change to wireframe mode */
  155.             wireframe = !wireframe;
  156.             }
  157.         else if (keyread==gkeys[0]) {
  158.             /* left turn */
  159.             angle -= DELTA_ANGLE * movefactor;
  160.             sprintf(com,"a %d %f",drive->vid,angle);
  161.             }
  162.         else if (keyread==gkeys[1]) {
  163.             /* right turn */
  164.             angle += DELTA_ANGLE * movefactor;
  165.             sprintf(com,"a %d %f",drive->vid,angle);
  166.             }
  167.         else if (keyread==gkeys[2]) {
  168.             /* accellerate */
  169.             velocity += DELTA_VELOCITY;
  170.             velocity = min(drive->max.velocity,velocity);
  171.             sprintf(com,"v %d %f",drive->vid,velocity);
  172.             }
  173.         else if (keyread==gkeys[3]) {
  174.             /* decellerate */
  175.             velocity -= DELTA_VELOCITY;
  176.             velocity = max(-drive->max.velocity,velocity);
  177.             sprintf(com,"v %d %f",drive->vid,velocity);
  178.             }
  179.         else if (keyread==gkeys[4] && drive->flying) {
  180.             /* increase altitude */
  181.             altitude += DELTA_ALT * movefactor;
  182.             sprintf(com,"c %d %f",drive->vid,altitude);
  183.             }
  184.         else if (keyread==gkeys[5] && drive->flying) {
  185.             /* decrease altitude */
  186.             altitude -= DELTA_ALT * movefactor;
  187.             sprintf(com,"c %d %f",drive->vid,altitude);
  188.             }
  189.         else if (keyread==gkeys[6]) {
  190.             /* come to a complete halt */
  191.             velocity = 0.0;
  192.             sprintf(com,"v %d 0.0",drive->vid);
  193.             }
  194.         else if (keyread==gkeys[7]) {
  195.             /* rotate gun left */
  196.             tangle -= DELTA_ANGLE * movefactor;
  197.             sprintf(com,"t %d %f",drive->vid,tangle);
  198.             }
  199.         else if (keyread==gkeys[8]) {
  200.             /* rotate gun right */
  201.             tangle += DELTA_ANGLE * movefactor;
  202.             sprintf(com,"t %d %f",drive->vid,tangle);
  203.             }
  204.         else if (keyread==gkeys[9]) {
  205.             /* fire gun */
  206.             sprintf(com,"f %d 0.0",drive->vid);
  207.             }
  208.         else if (keyread==gkeys[10]) {
  209.             /* quit game */
  210.             sprintf(com,"x %d 0.0",drive->vid);
  211.             }
  212.         else if (keyread==gkeys[12] && (*vmode==4 || *vmode==6)) {
  213.             /* attempt lock onto a target.
  214.              * The calculation of which vehicles the lock
  215.              * is made on is done now, and the victim
  216.              * transmitted to all clients.
  217.              */
  218.             int victim=-1;
  219.             struct vehicle *vpos;
  220.             float cdist=VIEW_RANGE;
  221.  
  222.             /* find the closest vehicle within 20 units
  223.              * of the line of sight from the player. 
  224.              */
  225.             for(vpos=vh; vpos; vpos=vpos->next) {
  226.                 struct object *ob;
  227.                 int j;
  228.                 if (vpos==drive || vpos->type==t_scenery)
  229.                     continue;
  230.                 for(j=0; j<vpos->partcount; j++) {
  231.                     int k;
  232.                     ob=vpos->parts[j];
  233.                     for(k=0; k<ob->pcount; k++) {
  234.                         float x,y,z;
  235.                         x=ob->cpoints[k].x;    
  236.                         y=ob->cpoints[k].y;    
  237.                         z=ob->cpoints[k].z;    
  238.                         if (z>0 && z<cdist &&
  239.                          (x*x + y*y)<20*20) {
  240.                             victim=vpos->vid;
  241.                             cdist=z;
  242.                             }
  243.                         }
  244.                     }
  245.                 }
  246.             sprintf(com,"l %d %d",drive->vid,victim);
  247.             }
  248.         else if (keyread==gkeys[13]) {
  249.             if (drive->type == t_tank || drive->type == t_hover ||
  250.              drive->type == t_fixedwing) {
  251.                 /* leave vehicle */
  252.                 sprintf(com,"j %d 0.0",drive->vid);
  253.                 }
  254.             }
  255.         else if (keyread==gkeys[14]) {
  256.             /* Toggle build icon bar */
  257.             buildicons = !buildicons;
  258.             }
  259.         else if (keyread==gkeys[15]) {
  260.             /* weapon tilted up */
  261.             turret_ang += DELTA_TURRET_ANG;
  262.             turret_ang = min(turret_ang,drive->max.turret_ang);
  263.             sprintf(com,"r %d %f",drive->vid,turret_ang);
  264.             }
  265.         else if (keyread==gkeys[16]) {
  266.             /* weapon tilted down */
  267.             turret_ang -= DELTA_TURRET_ANG;
  268.             turret_ang = max(turret_ang,-drive->max.turret_ang);
  269.             sprintf(com,"r %d %f",drive->vid,turret_ang);
  270.             }
  271.         break;
  272.  
  273.     case ConfigureNotify:
  274.         if (event.xconfigure.width != window_w || 
  275.          event.xconfigure.height != window_h) {
  276.             /* change in window size */
  277.             window_w=event.xconfigure.width;
  278.             window_h=event.xconfigure.height;
  279.             /* free old back buffer pixmap, and create
  280.              * a new one.
  281.              */
  282.             XFreePixmap(display,view_pm);
  283.             view_pm=XCreatePixmap(display,view_win,
  284.              window_w,window_h,8);
  285.             }
  286.         break;
  287.  
  288.     case ButtonPress:
  289.         if (!drive) {
  290.             /* The player is dead. Ignore any button presses. */
  291.             break;
  292.             }
  293.         switch(event.xbutton.button) {
  294.         case Button1:
  295.             if (event.xbutton.y > window_h-16 &&
  296.              event.xbutton.x < 13*16) {
  297.                 /* Send a build message */
  298.                 sprintf(com,"b %d %d\n",drive->vid,
  299.                  (event.xbutton.x/16)+1);
  300.                 }
  301.             break;
  302.             }
  303.         break;
  304.  
  305.     default:
  306.         /* some other x-event */
  307.         break;
  308.         }
  309.  
  310.     /* concatentate command from this event with list of commands
  311.      * to send to server */
  312.     strcat(msg,com);
  313.     strcat(msg," ");
  314.     }
  315.  
  316. /* if no key has been hit this frame, lower move multiplier */
  317. if (!keyhit && movefactor > 1)
  318.     movefactor -= 0.5;
  319.  
  320.  
  321. /* send off all commands to server (if the player is alive).
  322.  */
  323. if (singlep) {
  324.     /* Fake the fd method of passing commands when in single player
  325.      * mode. */
  326.     strcat(fakepipe,msg);
  327.     }
  328. else
  329.     nprintf(sock,"%s\n",msg);
  330. }
  331.  
  332. void createcamera(struct vehicle *drive, struct view *vw, int vmode, 
  333.  struct map *mp, struct vehicle *vhead)
  334. {
  335. double gun_angle;
  336. struct object *tur;
  337. struct vehicle *v=NULL;
  338.  
  339. switch(vmode) {
  340. case 1:
  341.     /* looking at vehicle, from far away */
  342.     vw->vrp.x=drive->parts[0]->pos.x + 200;
  343.     vw->vrp.y=drive->parts[0]->pos.y + 200;
  344.     vw->vrp.z=drive->parts[0]->pos.z + 200;
  345.     /* towards vehicle */
  346.     vw->n.x=-200;
  347.     vw->n.y=-200;
  348.     vw->n.z=-200;
  349.     /* up vector vertical */
  350.     vw->v.x=0; vw->v.y=0; vw->v.z=1;
  351.     break;
  352. case 2:
  353.     /* looking at your vehicle, from the map lookout position */
  354.     vw->vrp.x = mp->lookout.x;
  355.     vw->vrp.y = mp->lookout.y;
  356.     vw->vrp.z = mp->lookout.z;
  357.     /* towards vehicle */
  358.     vw->n.x = drive->parts[0]->pos.x - mp->lookout.x;
  359.     vw->n.y = drive->parts[0]->pos.y - mp->lookout.y;
  360.     vw->n.z = drive->parts[0]->pos.z - mp->lookout.z;
  361.     vw->v.x=0; vw->v.y=0; vw->v.z=1;
  362.     if (!vw->n.x && !vw->n.y && !vw->n.z) {
  363.         /* uh-oh! the vehicle is exactly at the point of the camera! */
  364.         vw->n.y = 1.0;
  365.         vw->v.x = 1.0;
  366.         }
  367.     else if (!vw->n.x && !vw->n.y) {
  368.         /* uh-oh! u and v are parrellel! */
  369.         vw->v.x = 1.0;
  370.         }
  371.     break;
  372. case 3:
  373.     /* looking from just behind vehicle */
  374.     vw->vrp.x = drive->parts[0]->pos.x - jcos(drive->angle)*70 + 10;
  375.     vw->vrp.y = drive->parts[0]->pos.y - jsin(drive->angle)*70;
  376.     vw->vrp.z = drive->parts[0]->pos.z + 60;
  377.     vw->n.x = jcos(drive->angle)*10;
  378.     vw->n.y = jsin(drive->angle)*10;
  379.     vw->n.z = -5;
  380.     vw->v.x=0; vw->v.y=0; vw->v.z=1;
  381.     break;
  382. case 4:
  383.     /* inside vehicle */
  384.     vw->vrp.x = drive->parts[0]->pos.x;
  385.     vw->vrp.y = drive->parts[0]->pos.y;
  386.     vw->vrp.z = drive->parts[0]->pos.z+5;
  387.     /* in direction of travel */
  388.     vw->n.x = jcos(drive->angle);
  389.     vw->n.y = jsin(drive->angle);
  390.     vw->n.z = 0;
  391.     vw->v.x=0; vw->v.y=0; vw->v.z=1;
  392.     break;
  393. case 5:
  394.     /* directly above vehicle */
  395.     vw->vrp.x = drive->parts[0]->pos.x;
  396.     vw->vrp.y = drive->parts[0]->pos.y;
  397.     vw->vrp.z = drive->parts[0]->pos.z + 200;
  398.     /* looking down onto it */
  399.     vw->n.x = 0;
  400.     vw->n.y = 0;
  401.     vw->n.z = -1;
  402.     vw->v.x = 1; vw->v.y = 0; vw->v.z = 0;
  403.     break;
  404. case 6:
  405.     /* gun turret view */
  406.     tur = findturret(drive);
  407.     if (!tur) {
  408.         /* no gun turret found */
  409.         gun_angle = drive->angle;
  410.         tur = drive->parts[0];
  411.         }
  412.     else {
  413.         /* vehicle has a gun turret */
  414.         gun_angle = tur->angle;
  415.         }
  416.     /* looking from gun turret */
  417.     vw->vrp.x = tur->pos.x;
  418.     vw->vrp.y = tur->pos.y;
  419.     vw->vrp.z = tur->pos.z+5;
  420.     /* in firing direction */
  421.     vw->n.x = jcos(gun_angle) * jcos(drive->turret_ang);
  422.     vw->n.y = jsin(gun_angle) * jcos(drive->turret_ang);
  423.     vw->n.z = jsin(drive->turret_ang);
  424.     /* usual up vector */
  425.     vw->v.x = 0;    vw->v.y = 0;    vw->v.z = 1.0;
  426.     break;
  427. case 7:
  428.     /* looking at vehicle, from close in */
  429.     vw->vrp.x=drive->parts[0]->pos.x + 50;
  430.     vw->vrp.y=drive->parts[0]->pos.y + 50;
  431.     vw->vrp.z=drive->parts[0]->pos.z + 50;
  432.     /* towards vehicle */
  433.     vw->n.x=-50;
  434.     vw->n.y=-50;
  435.     vw->n.z=-50;
  436.     /* up vector vertical */
  437.     vw->v.x=0; vw->v.y=0; vw->v.z=1;
  438.     break;
  439. case 8:
  440.     /* looking from the viewpoint of the last shot fired, or
  441.      * forward view if none.
  442.      */
  443.     if (drive->missile != -1) {
  444.         v = findbyvid(vhead,drive->missile);
  445.         }
  446.     if (!v) {
  447.         /* no missile found */
  448.         drive->missile = -1;
  449.         v=drive;
  450.         }
  451.     /* looking from projectile */
  452.     vw->vrp.x = v->parts[0]->pos.x;
  453.     vw->vrp.y = v->parts[0]->pos.y;
  454.     vw->vrp.z = v->parts[0]->pos.z;
  455.     /* in direction of travel */
  456.     vw->n.x = jcos(v->angle);
  457.     vw->n.y = jsin(v->angle);
  458.     vw->n.z = 0;
  459.     /* usual up vector */
  460.     vw->v.x = 0;    vw->v.y = 0;    vw->v.z = 1.0;
  461.     break;
  462. case 9:
  463.     /* looking at an interesting thing */
  464.     v = findbyvid(vhead,drive->vm9vid);
  465.     if (!v) {
  466.         /* Vehicle being looked at is gone.. change to
  467.          * look at player's vehicle.
  468.          */
  469.         /*
  470.         v = drive;
  471.         drive->vm9vid = drive->vid;
  472.         */
  473.         drive->vm9vid = -1;
  474.         break;
  475.         }
  476.     /* looking at vehicle, from close in */
  477.     vw->vrp.x=v->parts[0]->pos.x + 50;
  478.     vw->vrp.y=v->parts[0]->pos.y + 50;
  479.     vw->vrp.z=v->parts[0]->pos.z + 50;
  480.     /* towards vehicle */
  481.     vw->n.x=-50;
  482.     vw->n.y=-50;
  483.     vw->n.z=-50;
  484.     /* up vector vertical */
  485.     vw->v.x=0; vw->v.y=0; vw->v.z=1;
  486.     break;
  487.     }
  488. }
  489.  
  490. void printcontrols(void)
  491. {
  492. printf("Controls\n");
  493. printf("--------\n");
  494. printf("rotate left              - %-8s",keyname(gkeys[0]));
  495. printf("rotate right             - %s\n",keyname(gkeys[1]));
  496. printf("accellerate              - %-8s",keyname(gkeys[2]));
  497. printf("decellerate              - %s\n",keyname(gkeys[3]));
  498. printf("climb                    - %-8s",keyname(gkeys[4]));
  499. printf("dive                     - %s\n",keyname(gkeys[5]));
  500. printf("halt                     - %s\n",keyname(gkeys[6]));
  501. printf("\n");
  502. printf("gun left                 - %-8s",keyname(gkeys[7]));
  503. printf("gun right                - %s\n",keyname(gkeys[8]));
  504. printf("gun up                   - %-8s",keyname(gkeys[15]));
  505. printf("gun down                 - %s\n",keyname(gkeys[16]));
  506. printf("fire                     - %-8s",keyname(gkeys[9]));
  507. printf("lock on                  - %s\n",keyname(gkeys[12]));
  508. printf("eject                    - %s\n",keyname(gkeys[13]));
  509. printf("\n");    
  510. printf("quit                     - %s\n",keyname(gkeys[10]));
  511. printf("wireframe toggle         - %-8s",keyname(gkeys[11]));
  512. printf("build menu toggle        - %s\n",keyname(gkeys[14]));
  513. printf("\n");
  514. printf("long range view              - 1  view from stationary point   - 2\n");
  515. printf("view from behind vehicle     - 3  inside view                  - 4\n");
  516. printf("above view                   - 5  turret view                  - 6\n");
  517. printf("short range view             - 7  missile view                 - 8\n");
  518. printf("interesting thing view       - 9\n");
  519. }
  520.  
  521. /* read commands from the server to the client, and act on them
  522.  */
  523. double readnet(struct vehicle **vhead, struct object **ohead, 
  524.  bool *winner, int *drvid)
  525. {
  526. char *msg;                /* message received */
  527. char *com;                /* command part of message */
  528. int veh;                /* vehicle command is for */
  529. double param;                /* parameter of command */
  530. struct vehicle *v;            /* pointer to commanded vehicle */
  531. double gtime;                /* game time from server */
  532. int i;
  533.  
  534. if (singlep) {
  535.     /* Messages come from the client, using a global string to fake
  536.      * sending through a file desciptor. */
  537.     msg=fakepipe;
  538.     }
  539. else {
  540.     /* Message comes from the server. */
  541.     msg=ngets(sock);
  542.     }
  543. #if NETDEBUG
  544.     printf("received \"%s\"\n",msg);
  545. #endif
  546.  
  547. /* extract game time */
  548. gtime=atof(strtok(msg," "));
  549.  
  550. /* extract commands from the message. each command is in the format
  551.  * <command> <vehicle id> <parameter>
  552.  * Repeat until there are no more commands in the message.
  553.  */
  554. while((com=strtok(NULL," "))) {
  555.     char *vehstr, *paramstr;
  556.  
  557.     vehstr = strtok(NULL," ");
  558.     if (vehstr == NULL)
  559.         break;
  560.     veh = atoi(vehstr);
  561.     paramstr = strtok(NULL," ");
  562.     if (paramstr == NULL)
  563.         break;
  564.     param = atof(paramstr);
  565.     
  566.     /* find the vehicle structure command is for */
  567.     v = findbyvid(*vhead,veh);
  568.     if (!v && com[0] != 'w') {
  569.         /* The vehicle this command is for has been destroyed..
  570.          * tough luck.
  571.          */
  572.         continue;
  573.         }
  574.  
  575.     /* perform action based on command and parameters */
  576.     switch(com[0]) {
  577.     case 'a':
  578.         rotatevehicle(v,param);
  579.         break;
  580.     case 'v':
  581.         /* new velocity */
  582.         v->velocity = param;
  583.         break;
  584.     case 'c':
  585.         /* new altitude */
  586.         shiftvehicle(v,0,0,param - v->parts[0]->pos.z);
  587.         break;
  588.     case 't':
  589.         /* new turret angle */
  590.         for(i=0; i<v->partcount; i++)
  591.             if (v->parts[i]->turret) {
  592.                 rotatez(v->parts[i],param - v->parts[i]->angle);
  593.                 v->parts[i]->angle = param;
  594.                 }
  595.         break;
  596.     case 'f':
  597.         /* fire a shell */
  598.         fire(vhead,ohead,v);
  599.         break;
  600.     case 'x':
  601.         /* explode a vehicle */
  602.         v->hp = -1;
  603.         break;
  604.     case 'q':
  605.         /* game over */
  606.         printf("ALL PLAYERS DESTROYED... GAME OVER\n");
  607.         if (!singlep)
  608.             shutdown(sock,2);
  609.         close(sock);
  610.         exit(0);
  611.     case 'w':
  612.         /* someone has won the game */
  613.         *winner=true;
  614.         break;
  615.     case 'l':
  616.         /* a lock has been made */
  617.         v->lock = (int)param;
  618.         break;
  619.     case 'j':
  620.         /* a player has left their vehicle */
  621.         eject(vhead,ohead,v);
  622.         v->owner = o_none;
  623.         if (v->vid == *drvid) {
  624.             /* the ejected player is the current one!
  625.              * Change the player's vid to that of the
  626.              * new creature.
  627.              */
  628.             *drvid = (*vhead)->vid;
  629.             }
  630.         break;
  631.     case 'b':
  632.         /* a player has construced something */
  633.         build(vhead,ohead,v,param);
  634.         break;
  635.     case 'r':
  636.         /* a player has raised/lowered their turret */
  637.         v->turret_ang = param;
  638.         break;
  639.     default:
  640.         printf("Unknown command from server!!\n");
  641.         exit(5);
  642.         }
  643.     }
  644. if (singlep)
  645.     fakepipe[0] = '\0';
  646. return gtime;
  647. }
  648.  
  649. void controlvehicles(struct vehicle **vhead, struct object **ohead)
  650. {
  651. struct vehicle *v;
  652. static int recalc=30;            /* calls till next re-calculation */
  653.                     /* of target or threat */
  654.  
  655. if (recalc-- == 0)
  656.     recalc=30;
  657. for(v=*vhead; v; v=v->next) {
  658.     /* Use brain system if this vehicle has one.
  659.      */
  660.     if (v->currentstate != -1 && v->owner == o_game) {
  661.         think(v,vhead,ohead);
  662.         continue;
  663.         }
  664.  
  665.     if (v->target == -2) {
  666.         /* no possible targets. */
  667.         continue;
  668.         }
  669.     /* only consider vehicles controlled by the computer and
  670.      * potentially hostile.
  671.      */
  672.     if (v->owner==o_game && v->type!=t_scenery && v->type!=t_static &&
  673.      v->type!=t_bullet && v->type!=t_shrapnel) {
  674.         struct vehicle *t=NULL;
  675.  
  676.         /* find a target if this vehicle has none.
  677.          * Re-check this target every 30 frames, except for
  678.          * the case of missiles, which remain locked onto the
  679.          * one victim until they hit.
  680.          */
  681.         if (v->target==-1 || (recalc==0 && v->type!=t_missile)) {
  682.             struct vehicle *p;
  683.             float mdis=VIEW_RANGE*VIEW_RANGE;
  684.             float dist;
  685.  
  686.             /* find the closest possible target */
  687.             for(p=*vhead; p; p=p->next) {
  688.                 if (possibletarget(v,p)) {
  689.                     dist=vehicledist(v,p);
  690.                     if (dist < mdis) {
  691.                         mdis=dist;
  692.                         t=p;
  693.                         }
  694.                     }
  695.                 }
  696.             /* lock on if a target was found */
  697.             if (t) {
  698.                 v->target=t->vid;
  699.                 /*
  700.                 printf("%s locked onto %s\n",v->code,t->code);
  701.                 */
  702.                 }
  703.             }
  704.         else {
  705.             /* find the vehicle structure correspoding.
  706.              * to the target vid.
  707.              */ 
  708.             t = findbyvid(*vhead,v->target);
  709.             }
  710.         if (!t) {            /* no valid target found */
  711.             if (v->target == -1) {
  712.                 /* no target was found last time either,
  713.                  * so there can be none. give up looking.
  714.                  */
  715.                 v->target=-2;
  716.                 continue;
  717.                 }
  718.             else {
  719.                 v->target=-1;
  720.                 continue;
  721.                 }
  722.             }
  723.         /* computer-controlled vehicle/thing */
  724.         switch(v->type) {
  725.         case  t_tank: {
  726.             /* adjust heading to head for a target, and
  727.              * fire a shot if close to the right angle
  728.              * and at the right height.
  729.              */
  730.             v->angle_vel = vehicleangle(v,t)-v->angle;
  731.             if (v->angle_vel < -PI)
  732.                 v->angle_vel += 2*PI;
  733.  
  734.             v->velocity = v->max.velocity/2.0;
  735.  
  736.             /* if pointing the right way ... */
  737.             if (dabs(v->angle_vel) < dtor(1.0)) {
  738.                 /* ... and not flying too far above ...  */
  739.                 if (dabs(heightdiff(t,v)) < 5.0) {
  740.                     /* ... fire a shot */
  741.                     fire(vhead,ohead,v);
  742.                     }
  743.                 }
  744.             break;
  745.             }
  746.         case t_hover: {
  747.             /* adjust heading to approach target, and
  748.              * climb to it's altitude. fire when on line.
  749.              */
  750.             v->angle_vel = vehicleangle(v,t) - v->angle;
  751.             if (v->angle_vel < -PI)
  752.                 v->angle_vel += 2*PI;
  753.             v->velocity = 20;
  754.             v->climb = heightdiff(t,v);
  755.             v->velocity = v->max.velocity/2.0;
  756.             if (dabs(v->angle_vel) < dtor(0.1) &&
  757.              dabs(v->climb) < 5.0)
  758.                 fire(vhead,ohead,v);
  759.             break;
  760.             }
  761.         case t_bird: {
  762.             /* run away from the nearest fish or player */
  763.             double awaydir;
  764.  
  765.             awaydir = vehicleangle(v,t)+PI;
  766.             v->angle_vel = awaydir - v->angle;
  767.             if (v->angle_vel < -PI)
  768.                 v->angle_vel += 2*PI;
  769.             else if (v->angle_vel > PI)
  770.                 v->angle_vel -= 2*PI;
  771.             v->velocity = v->max.velocity;
  772.             break;
  773.             }
  774.         case t_fish: {
  775.             /* chase the nearest bird.
  776.              */
  777.             v->angle_vel = vehicleangle(v,t) - v->angle;
  778.             if (v->angle_vel < -PI)
  779.                 v->angle_vel += 2*PI;
  780.             v->climb = heightdiff(t,v)/3.0;
  781.             v->velocity = v->max.velocity;
  782.             break;
  783.             }
  784.         case t_missile: {
  785.             /* follow the target */
  786.             v->angle_vel = vehicleangle(v,t) - v->angle;
  787.             if (v->angle_vel < -PI)
  788.                 v->angle_vel += 2*PI;
  789.             v->climb = heightdiff(t,v)/3.0;
  790.  
  791.             v->velocity = v->max.velocity;
  792.             break;
  793.             }
  794.         case t_gunsite: {
  795.             /* rotate to target */
  796.             v->angle_vel = vehicleangle(v,t) - v->angle;
  797.             if (v->angle_vel < -PI)
  798.                 v->angle_vel += 2*PI;
  799.             /* consider firing */
  800.             if (dabs(v->angle_vel) < dtor(1.0)) {
  801.                 /* adjust firing angle upwards. */
  802.                 v->turret_ang = atan2(heightdiff(t,v),
  803.                               sqrt(vehicledist(t,v)));
  804.                 if (dabs(v->turret_ang) < v->max.turret_ang)
  805.                     fire(vhead,ohead,v);
  806.                 }
  807.             break;
  808.             }
  809.         case t_shrapnel:    /* Uncontrolled vehicles.
  810.         case t_static:         */
  811.         case t_bullet:
  812.         case t_static:
  813.         case t_scenery:
  814.         case t_fixedwing:
  815.         case t_thing:
  816.         case t_tree:
  817.         case t_seedpod:
  818.         case t_mine:
  819.         case t_weapon:
  820.         case t_munitions:
  821.             break;
  822.             }
  823.         }
  824.     }
  825. }
  826.  
  827. /* calculates the angle from vehicle s to vehicle d (in the x/y plane) */
  828. double vehicleangle(struct vehicle *s, struct vehicle *d)
  829. {
  830. float xd,yd;
  831. float ang;
  832. xd = d->parts[0]->pos.x - s->parts[0]->pos.x;
  833. yd = d->parts[0]->pos.y - s->parts[0]->pos.y;
  834. ang=atan2(yd,xd);
  835. return ang<0 ? ang+PI*2 : ang;
  836. }
  837.  
  838. /* read key definitions in from the key configuration file.
  839.  */
  840. void readkeyfile(FILE *fp)
  841. {
  842. char *keynames[]={"left", "right", "accel", "decel", "climb",
  843.           "dive", "stop", "gunleft", "gunright",
  844.           "fire", "quit", "wireframe", "lock",
  845.           "eject", "menu", "gunup", "gundown", NULL};
  846.  
  847. printf("reading %s\n",KEYFILE);
  848. while(!feof(fp)) {
  849.     char lbuf[100]="";        /* a line from the file */
  850.     char *comn;            /* command key is for */
  851.     char *key;            /* key code */
  852.     int i;
  853.  
  854.     /* read in a line from the file */
  855.     fgets(lbuf,100,fp);
  856.     lbuf[strlen(lbuf)-1] = '\0';
  857.     if (!strlen(lbuf))
  858.         continue;
  859.  
  860.     /* extract command from the line */
  861.     comn=strtok(lbuf," \t\n");
  862.     if (!comn) {
  863.         printf("you must give a command name on each line\n");
  864.         exit(1);
  865.         }
  866.     for(i=0; keynames[i] && strncmp(comn,keynames[i],
  867.      strlen(keynames[i])); i++)
  868.         ;
  869.     if (!keynames[i]) {
  870.         printf("%s is not a valid command\n",comn);
  871.         printf("valid commands for keys are : \n");
  872.         for(i=0; keynames[i]; i++)
  873.             printf("%s ",keynames[i]);
  874.         printf("\n");
  875.         exit(1);
  876.         }
  877.  
  878.     /* extract key assignment from line */
  879.     key=strtok(NULL," \t\n");
  880.     if (!key) {
  881.         printf("you must give a key for command %s\n",comn);
  882.         exit(5);
  883.         }
  884.     if (!strcmp(key,"return"))
  885.         gkeys[i]=XK_Return;
  886.     else if (!strcmp(key,"space"))
  887.         gkeys[i]=XK_space;
  888.     else if (!strcmp(key,"delete"))
  889.         gkeys[i]=XK_Delete;
  890.     else if (!strcmp(key,"escape"))
  891.         gkeys[i]=XK_Escape;
  892.     else if (!strcmp(key,"backspace"))
  893.         gkeys[i]=XK_BackSpace;
  894.     else if (!strcmp(key,"tab"))
  895.         gkeys[i]=XK_Tab;
  896.     else if (!strcmp(key,"left"))
  897.         gkeys[i]=XK_Left;
  898.     else if (!strcmp(key,"right"))
  899.         gkeys[i]=XK_Right;
  900.     else if (!strcmp(key,"up"))
  901.         gkeys[i]=XK_Up;
  902.     else if (!strcmp(key,"down"))
  903.         gkeys[i]=XK_Down;
  904.     else if (atoi(key))
  905.         gkeys[i]=atoi(key);
  906.     else
  907.         gkeys[i]=key[0];
  908.     }
  909. }
  910.  
  911. /* return a description of a given XK code */
  912. char *keyname(int k)
  913. {
  914. static char knbuf[20];
  915.  
  916. if (k > 32 && k < 128) {
  917.     /* key is a simple printable character */
  918.     sprintf(knbuf,"%c",k);
  919.     }
  920. /* unprintable but named keys */
  921. else if (k==XK_Return)
  922.     sprintf(knbuf,"return");
  923. else if (k==XK_space)
  924.     sprintf(knbuf,"space");
  925. else if (k==XK_Delete)
  926.     sprintf(knbuf,"delete");
  927. else if (k==XK_Escape)
  928.     sprintf(knbuf,"escape");
  929. else if (k==XK_BackSpace)
  930.     sprintf(knbuf,"backspace");
  931. else if (k==XK_Tab)
  932.     sprintf(knbuf,"tab");
  933. else if (k==XK_Left)
  934.     sprintf(knbuf,"left");
  935. else if (k==XK_Right)
  936.     sprintf(knbuf,"right");
  937. else if (k==XK_Up)
  938.     sprintf(knbuf,"up");
  939. else if (k==XK_Down)
  940.     sprintf(knbuf,"down");
  941. else {
  942.     /* key is an unknown character */
  943.     sprintf(knbuf,"ascii %d",k);
  944.     }
  945. return knbuf;
  946. }
  947.  
  948. bool possibletarget(struct vehicle *v, struct vehicle *targ)
  949. {
  950. /* prevent a vehicle locking onto itself */
  951. if (v == targ)
  952.     return false;
  953. /* find out what interests each vehicle type */
  954. switch(v->type) {
  955. case t_tank:
  956. case t_hover:
  957.     /* armoured vehicles chase after the nearest player */
  958.     if (targ->owner==o_player || targ->owner==o_network)
  959.         return true;
  960.     break;
  961. case t_fish:
  962.     /* fish chase after the nearest bird */
  963.     if (targ->type==t_bird)
  964.         return true;
  965.     break;
  966. case t_bird:
  967.     /* birds fly away from fish */
  968.     if (targ->type == t_fish || targ->owner == o_player ||
  969.      targ->owner == o_network)
  970.         return true;
  971.     break;
  972. case t_gunsite:
  973.     /* a gunsite shoots at any nearby vehicle, except for it's
  974.      * builder and other gunsites.
  975.      */
  976.     if (targ->vid != v->buildervid && !boring(targ) &&
  977.      targ->type != t_gunsite)
  978.         return true;
  979.     break;
  980. case t_shrapnel:    /* Uncontrolled vehicles.
  981. case t_static:         */
  982. case t_bullet:
  983. case t_static:
  984. case t_scenery:
  985. case t_fixedwing:
  986. case t_thing:
  987. case t_tree:
  988. case t_missile:
  989. case t_seedpod:
  990. case t_mine:
  991. case t_weapon:
  992. case t_munitions:
  993.     break;
  994.     }
  995. return false;
  996. }
  997.  
  998. void growtrees(struct vehicle **vh, struct object **oh)
  999. {
  1000. struct vehicle *v, *vnext;
  1001. struct object *o;
  1002. int i,j;
  1003. static int call=0;
  1004. bool exploded;
  1005.  
  1006. for(v=*vh; v; v = vnext) {
  1007.     vnext = v->next;
  1008.     if (v->type == t_tree && (call=(call+1)%61) == 0) {
  1009.         exploded=false;
  1010.         for(i=0; i<v->partcount; i++) {
  1011.             float maxht=0;
  1012.  
  1013.             o = v->parts[i];
  1014.             for(j=0; j<o->pcount; j++) {
  1015.                 o->points[j].z *= GROWTHRATE;
  1016.                 if (o->points[j].z > maxht)
  1017.                     maxht = o->points[j].z;
  1018.                 }
  1019.             if (maxht > v->max.treeheight) {
  1020.                 /* Explode this tree! */
  1021.                 explode(vh,oh,v);
  1022.                 exploded = true;
  1023.                 break;
  1024.                 }
  1025.             }
  1026.         if (!exploded)
  1027.             calcbbox(v);
  1028.         }
  1029.     }
  1030. }
  1031.  
  1032. /* build - a vehicle has just attemped to build something.
  1033.  *
  1034.  * vh        - head of the vehicle list
  1035.  * oh        - head of the object list
  1036.  * v        - vehicle doing the building
  1037.  * w        - the type of thing it is attempting to build
  1038.  */
  1039. void build(struct vehicle **vh, struct object **oh, struct vehicle *v, int w)
  1040. {
  1041. struct vehicle *nv;
  1042. char wallname[100];
  1043. struct point pos;
  1044. int i;
  1045.  
  1046. /* check if the builder has enough resources */
  1047. if (v->res < wallcost[w])
  1048.     return;
  1049.  
  1050. /* create a new vehicle structure, and add it to the list */
  1051. nv = (struct vehicle *)calloc(1,sizeof(struct vehicle));
  1052. nv->parts = (struct object **)calloc(MAX_PARTS_PER_VEHICLE,
  1053.                      sizeof(struct object *));
  1054. nv->next = *vh;
  1055. *vh = nv;
  1056.  
  1057. /* find the wall vehicle to copy from. Then copy it, and set it's 
  1058.  * attributes.
  1059.  */
  1060. sprintf(wallname,"wall%d",w);
  1061. copyvehicle(nv,findbycode(evhead,wallname),oh);
  1062. nv->code = strdupe("wall");
  1063. nv->owner = o_game;
  1064. nv->alive = true;
  1065. nv->vid = vidcount++;
  1066. nv->buildervid = v->vid;
  1067.  
  1068. /* rotate the new wall bit to line up in front of the player, and
  1069.  * shift it out away from the player's vehicle.
  1070.  */
  1071. pos = v->parts[0]->pos;
  1072. pos.x += jcos(v->angle)*10;
  1073. pos.y += jsin(v->angle)*10;
  1074. for(i=0; i<nv->partcount; i++) {
  1075.     rotatez(nv->parts[i],v->angle);
  1076.     nv->parts[i]->pos.x += pos.x;
  1077.     nv->parts[i]->pos.y += pos.y;
  1078.     nv->parts[i]->pos.z += pos.z;
  1079.     }
  1080. nv->angle += v->angle;
  1081. calcbbox(nv);
  1082.  
  1083. if (collide(nv,*vh)) {
  1084.     /* uh, oh! This new wall section will collide with something
  1085.      * already in place! Get rid of the new wall.
  1086.      */
  1087.     freevehicle(nv,vh,oh);
  1088.     XBell(display,30);
  1089.     }
  1090. else {
  1091.     /* success! charge the builder */
  1092.     v->res -= wallcost[w];
  1093.     }
  1094. }
  1095.  
  1096.  
  1097. /* boring - returns true if the vehicle given is only a minor player in
  1098.  * the game, such as a bullet, house or fragment of shrapnel.
  1099.  */
  1100. bool boring(struct vehicle *v)
  1101. {
  1102. if (v->type == t_static || v->type == t_scenery || v->type == t_bullet ||
  1103.  v->type == t_tree || v->type == t_seedpod || v->type == t_shrapnel ||
  1104.  v->type == t_mine || v->type == t_munitions)
  1105.     return true;
  1106. else
  1107.     return false;
  1108. }
  1109.  
  1110. /* function to be called if ctrl-c is hit.
  1111.  */
  1112. void termhandler(int s)
  1113. {
  1114. ctrlc = 1;
  1115. }
  1116.  
  1117.  
  1118. /* xerrorhandler - called when a fatal X error occurs, typically due to
  1119.  * a destroyed window.
  1120.  */
  1121. int xerrorhandler(Display *dis)
  1122. {
  1123. nprintf(sock,"d\n");
  1124. XFreePixmap(display,view_pm);
  1125. XFlush(display);
  1126. if (fork())
  1127.     exit(0);
  1128. else
  1129.     deadloop();
  1130. return 0;
  1131. }
  1132.  
  1133. /* Called after ctrl-c has been hit, to convince the server that this
  1134.  * player is still active.
  1135.  */
  1136. void deadloop(void)
  1137. {
  1138. while(1) {
  1139.     char *fromserv;
  1140.     char *com;
  1141.  
  1142.     /* send an empty line to convince the server that this player is
  1143.      * still around. */
  1144.     nprintf(sock,"\n");
  1145.  
  1146.     /* soak up a line from the server.
  1147.      */
  1148.     fromserv = ngets(sock);
  1149.     strtok(fromserv," ");
  1150.     while((com = strtok(NULL," "))) {
  1151.         strtok(NULL," ");
  1152.         strtok(NULL," ");
  1153.         if (com[0] == 'q') {
  1154.             /* game over */
  1155.             shutdown(sock,2);
  1156.             close(sock);
  1157.             exit(0);
  1158.             }
  1159.         }
  1160.     }
  1161. }
  1162.  
  1163.